/*  led-drv.c - The simplest kernel module.

* Copyright (C) 2013 - 2016 Xilinx, Inc
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.

*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License along
*   with this program. If not, see <http://www.gnu.org/licenses/>.

*/

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/kernel.h>
#include "ar0234.h"

#define STREAM_MODE 1  //流模式
#define TRIGGER_MODE 0 //触发模式

//字符设备结构体
struct i2c_dev
{
	dev_t devid;	  //设备号
	int major;		  //主设备号
	int minor;		  //副设备号
	struct cdev cdev; //字符设备
	struct class *class;
	struct device *device;
	struct device_node *node;
	int cam_emio[2];	//cam_emio[0]为camera gpio，cam_emio[1]为camera trigger
	int imu_emio;		//imu_trigger
	void *private_data; //私有数据，用来保存probe函数传递进来的i2c_client结构体

	struct hrtimer htimer; //高精度定时器
	ktime_t htimeperiod;

	/** 等待队列 **/
	wait_queue_head_t wait_q_h; //等待队列头
	// int is_ready;

	spinlock_t lock; 
	atomic_t is_ready;//
};

#define DEVICE_COUNT 1
#define DEVICE_NAME "OV5640"

char writebuf[5];
struct i2c_dev ov5640;

int ov5640_probe(struct i2c_client *client, const struct i2c_device_id *id);
int ov5640_remove(struct i2c_client *client);

//读取OV5640某个寄存器数据
static int ov5640_read_regs(struct i2c_dev *dev, u16 reg, void *val, int len)
{
	int ret = 0;
	struct i2c_client *client = (struct i2c_client *)dev->private_data;
	struct i2c_msg msg[2];
	u8 reg_buf[2];					  //将16位地址拆分成两个8位
	reg_buf[0] = (reg & 0xff00) >> 8; //高八位
	reg_buf[1] = reg & 0x00ff;		  //低八位
	//配置struct i2c_msg *msgs，msg[0]为发送要读取的寄存器首地址
	msg[0].addr = client->addr; //从机地址
	msg[0].flags = 0;			//0为向从机进行写操作
	msg[0].buf = reg_buf;		//buf为要发送的数据，先发送要进行读操作读寄存器地址
	msg[0].len = 2;				//寄存器地址的长度为1
	//配置struct i2c_msg *msgs，msg[1]发送要读取的寄存器首地址
	msg[1].addr = client->addr; //从机地址
	msg[1].flags = I2C_M_RD;	//向从机进行读操作
	msg[1].buf = val;			//从从机读取的数据保存到val里
	msg[1].len = len;			//从从机读取的数据长度,寄存器为16位
	//i2c_transfer可以对寄存器进行读和写，需要对struct i2c_msg *msgs进行配置实现读或者写数据
	ret = i2c_transfer(client->adapter, msg, 2);
	if (ret != 2)
	{
		printk("OV5640 read regs fail!\r\n");
		return -1;
	}
	return ret;
}

//读取OV5640某个寄存器数据
static int ov5640_read_reg(struct i2c_dev *dev, u16 reg, void *val)
{
	int ret = 0;
	ret = ov5640_read_regs(dev, reg, val, 2); //寄存器为16位，len要置为2
	return ret;
}

//向OV5640的某个寄存器写数据
static int ov5640_write_regs(struct i2c_dev *dev, u16 reg, u16 buf, int len)
{
	u8 b[256];
	int ret = 0;
	struct i2c_client *client = (struct i2c_client *)dev->private_data;
	struct i2c_msg msg;
	//
	b[0] = (reg & 0xff00) >> 8; //高八位
	b[1] = reg & 0x00ff;		//低八位					//数据首位为寄存器地址
	b[2] = (buf & 0xff00) >> 8; //高八位
	b[3] = buf & 0x00ff;		//低八位
	//配置struct i2c_msg *msgs
	msg.addr = client->addr; //从机地址
	msg.flags = 0;			 //0为向从机进行写操作
	msg.buf = b;			 //buf为要发送的数据，实际数据+寄存器地址
	msg.len = 2 + len;		 //要发送的数据长度：实际数据长度+寄存器地址长度
	ret = i2c_transfer(client->adapter, &msg, 1);
	if (ret != 1)
	{
		printk("OV5640 write regs fail!\r\n");
		return -1;
	}
	return ret;
}

//向OV5640的某个寄存器写数据
static int ov5640_write_reg(struct i2c_dev *dev, u16 reg, u16 data)
{
	int ret = 0;
	ret = ov5640_write_regs(dev, reg, data, 2); //寄存器为16位，len要置为2
	return ret;
}

static int sensor_init(struct i2c_dev *dev)
{
	int ret = 0;
	char sensor_id[2];
	ov5640_read_regs(&ov5640, 0x3000, &sensor_id[0], 1);
	ov5640_read_regs(&ov5640, 0x3001, &sensor_id[1], 1);
	if (sensor_id[0] != 0x0A || sensor_id[1] != 0x56)
	{
		printk("Not AR0144 id, %x %x\r\n", sensor_id[0], sensor_id[1]);
		goto error_id;
	}
	else
	{
		printk("Got AR0144 id, %x %x\r\n", sensor_id[0], sensor_id[1]);
	}
	int i = 0;
	while (AR0234[i].reg != SEQUENCE_END)
	{
		ret = ov5640_write_reg(dev, AR0234[i].reg, AR0234[i].val);
		if (ret < 0)
		{
			printk("register[%d] write fail!\r\n", i);
			goto fail_write;
		}
		i++;
	}
	// ret = ov5640_write_reg(dev,0x301A,0x0958);
	// if(ret<0)
	// {
	// 	printk("register 0x301A write fail!\r\n");
	// 	goto fail_write;
	// }
	return 0;
fail_write:
error_id:
	return -1;
}

static int ov5640_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &ov5640;
	printk("OV5640 open!\r\n");

	return 0;
}

static ssize_t ov5640_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{
	int ret = 0;
	unsigned char databuf[1];
	/*获取私有数据*/
	struct i2c_dev *dev = file_p->private_data;

	ret = copy_from_user(databuf, buf, len);
	if (ret < 0)
	{
		printk("imu_trigger write fail!\r\n");
	}

	// if (databuf[0] == 1)
	// {
	// 	// printk("trigger!\r\n");
	// 	gpio_set_value(dev->imu_emio, 1);
	// 	udelay(1);
	// 	gpio_set_value(dev->imu_emio, 0);
	// }
	return 0;
};

unsigned int ov5640_poll(struct file *file_p, struct poll_table_struct *wait)
{
	unsigned int ret = 0;

	poll_wait(file_p, &(ov5640.wait_q_h), wait);

	if (atomic_read(&ov5640.is_ready) == 1)
	{
		ret = POLLIN;
		// udelay(1);
		atomic_set(&ov5640.is_ready,0);
		//printk("is_ready=%d",ov5640.is_ready);
	}

	// udelay(1);
	//printk("ljis_ready=%d",ov5640.is_ready);
	return ret;
};

static int ov5640_release(struct inode *inode, struct file *filp)
{
	struct i2c_dev *ov5640 = filp->private_data;
	filp->private_data = NULL;
	printk("OV5640 release!\r\n");
	return 0;
}

static const struct file_operations ov5640_fops = {
	.owner = THIS_MODULE,
	.open = ov5640_open,
	.write = ov5640_write,
	.poll = ov5640_poll,
	.release = ov5640_release,
};

// static enum hrtimer_restart hrtimer_hander(struct hrtimer *timer)
// {
// 	// printk("I am in hrtimer hander\r\n");
// 	gpio_set_value(ov5640.imu_emio, 1);
// 	udelay(1);
// 	gpio_set_value(ov5640.imu_emio, 0);
// 	// mdelay(30);
// 	// kill_fasync(&vdma.async_queue, SIGIO, POLL_IN);
// 	// udelay(5);
// 	// ov5640.is_ready = 1;
// 	atomic_set(&ov5640.is_ready,1);
// 	wake_up_interruptible(&ov5640.wait_q_h);
// 	// printk("ov5640.is_ready = %d\r\n", ov5640.is_ready);
// 	hrtimer_forward_now(&ov5640.htimer, ov5640.htimeperiod);
// 	// hrtimer_forward(&vdma.htimer,&vdma.htimer->base->get_time(),vdma.htimeperiod);//hrtimer_forward(timer, now, tick_period);
// 	return HRTIMER_RESTART; //重启定时器
// }

static int ov5640_init(struct i2c_dev *dev)
{
	int ret = 0;
	//1.创建字符设备号
	dev->major = 0;
	if (dev->major) //给定设备号
	{
		dev->devid = MKDEV(dev->major, 0);
		ret = register_chrdev_region(dev->devid, DEVICE_COUNT, DEVICE_NAME);
	}
	else
	{
		ret = alloc_chrdev_region(&dev->devid, 0, DEVICE_COUNT, DEVICE_NAME);
	}
	if (ret < 0)
	{
		printk("fail to register!\r\n");
		goto fail_register;
	}
	dev->major = MAJOR(dev->devid);
	dev->minor = MINOR(dev->devid);
	printk("OV5640 MAJOR = %d!\r\n", dev->major);
	// printk("OV5640 MINOR = %d!\r\n", dev->minor);
	printk("dev->is_ready = 0;\r\n");
	//2.添加字符设备
	dev->cdev.owner = THIS_MODULE;
	cdev_init(&dev->cdev, &ov5640_fops);
	ret = cdev_add(&dev->cdev, dev->devid, DEVICE_COUNT);
	if (ret < 0)
	{
		printk("fail to create cdevice!\r\n");
		goto fail_cdev;
	}
	//3.自动创建设备节点
	dev->class = class_create(THIS_MODULE, DEVICE_NAME); //创建类
	if (IS_ERR(dev->class))
	{
		printk("fail to create class!\r\n");
		goto fail_class;
	}
	dev->device = device_create(dev->class, NULL, dev->devid, NULL, DEVICE_NAME); //创建设备
	if (IS_ERR(dev->device))
	{
		printk("fail to create device!\r\n");
		goto fail_device;
	}
	//4.获取camera所对应的GPIO
	// dev->cam_emio[0] = of_get_named_gpio(dev->node, "CAM0_EMIO", 0);
	// if (dev->cam_emio[0] < 0)
	// {
	// 	printk("fail to get name!\r\n");
	// 	goto fail_get_name;
	// }
	// dev->imu_emio = of_get_named_gpio(dev->node, "IMU_Trigger", 0);
	// if (dev->imu_emio < 0)
	// {
	// 	printk("fail to get name!\r\n");
	// 	goto fail_get_name;
	// }
	// printk("imu_emio = %d\r\n", dev->imu_emio);
	// //5.申请IO
	// ret = gpio_request(dev->imu_emio, "imu_gpio");
	// if (ret)
	// {
	// 	printk("fail to request gpio!\r\n");
	// 	goto fail_gpio_request;
	// }
	// //6.使用GPIO
	// ret = gpio_direction_output(dev->imu_emio, 0); //设置IO为输出，默认为0低电平（暗）
	// if (ret < 0)
	// {
	// 	goto fail_set_output;
	// }

	/*
&i2c0 {
	status = "okay";
	clock-frequency = <100000>;
	ov5640_l@10{			//ov5640
		compatible = "ov5640_l";
		reg = <0x10>;
		CAM0_EMIO 	 = <&gpio 78 GPIO_PULL_DOWN>;					//默认为低电平
		CAM_Trigger	 = <&gpio 81 GPIO_PULL_DOWN>;					//camera 0 Trigger 默认为低电平
	};
};
	*/

	// dev->is_ready = 0;

	atomic_set(&dev->is_ready,0);

	// dev->htimeperiod = ktime_set(0, 5000000); //5ms
	// //高精度定时器
	// hrtimer_init(&dev->htimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	// hrtimer_start(&dev->htimer, dev->htimeperiod, HRTIMER_MODE_REL);
	// dev->htimer.function = hrtimer_hander;

	init_waitqueue_head(&dev->wait_q_h);
	printk("OV5640 init!\r\n");
	return 0;

// fail_set_output:
// 	gpio_free(dev->imu_emio);

// fail_gpio_request:
// 	gpio_free(dev->imu_emio);
fail_get_name:
	device_destroy(dev->class, dev->devid);
fail_device:
	class_destroy(dev->class);
fail_class:
	cdev_del(&dev->cdev);
fail_cdev:
	unregister_chrdev_region(dev->devid, DEVICE_COUNT);
fail_register:
	printk("OV5640 init fail!\r\n");
	return -1;
}

static void ov5640_exit(struct i2c_dev *dev)
{
	// gpio_set_value(dev->cam_emio[0], 0);
	// // gpio_set_value(dev->cam_emio[1],0);
	// gpio_free(dev->cam_emio[0]);
	// gpio_free(dev->imu_emio);
	hrtimer_cancel(&dev->htimer);
	// gpio_free(dev->cam_emio[1]);
	device_destroy(dev->class, dev->devid);				//摧毁设备
	class_destroy(dev->class);							//摧毁类
	cdev_del(&dev->cdev);								//注销字符设备
	unregister_chrdev_region(dev->devid, DEVICE_COUNT); //注销字符设备号
	printk("OV5640 exit!\r\n");
}

static struct of_device_id ov5640_of_match[] = {
	{.compatible = "ov5640-l"},
	{/* Sentinel*/},
};

static struct i2c_driver ov5640_i2c_driver = {
	.probe = ov5640_probe,
	.remove = ov5640_remove,
	.driver = {
		.name = "ov5640-l",
		.owner = THIS_MODULE,
		.of_match_table = ov5640_of_match,
	},

};
//当probe函数执行后，probe函数传递的第一个变量struct i2c_client *client，它是驱动和设备匹配之后系统分配的i2c_client结构体，用来表示具体的设备
//i2c_client有个成员变量struct i2c_adapter *adapter，保存了此i2c设备所对应的i2c适配器
int ov5640_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	//获取设备树节点
	ov5640.node = client->dev.of_node;
	if (IS_ERR(ov5640.node))
	{
		printk("fail to find node!\r\n");
		goto fail_find_node;
	}
	//搭建字符设备框架，在/dev/下创建文件
	ov5640_init(&ov5640);
	ov5640.private_data = client; //将i2c_client结构体保存到设备结构体的私有数据中
	int ret = 0;
	// gpio_set_value(ov5640.cam_emio[0],0);
	// msleep(5);
	// gpio_set_value(ov5640.cam_emio[0],1);
	// ssleep(1);
	ret = sensor_init(&ov5640);
	if (ret < 0)
	{
		goto fail_init;
	}
	char value[2];
	ov5640_read_reg(&ov5640, 0x3002, value);
	printk("reg 0x3002 =%x %x\r\n", value[0], value[1]);
	ov5640_read_reg(&ov5640, 0x3004, value);
	printk("reg 0x3004 =%x %x\r\n", value[0], value[1]);
	// gpio_set_value(ov5640.cam_emio[1],1);
	// msleep(1);
	// gpio_set_value(ov5640.cam_emio[1],0);
	// msleep(30);
	// gpio_set_value(ov5640.cam_emio[1],1);
	// msleep(1);
	// gpio_set_value(ov5640.cam_emio[1],0);
	return 0;
fail_init:
	printk("sensor_init fail!\r\n");
fail_find_node:
	return -1;
}

int ov5640_remove(struct i2c_client *client)
{
	ov5640_exit(&ov5640);
	return 0;
}

//驱动入口函数
static int __init i2c_dev_init(void)
{
	i2c_add_driver(&ov5640_i2c_driver);
	return 0;
}

//驱动出口函数
static void __exit i2c_dev_exit(void)
{
	i2c_del_driver(&ov5640_i2c_driver);
}

module_init(i2c_dev_init);
module_exit(i2c_dev_exit);

/* 驱动描述信息 */
MODULE_AUTHOR("CCR");
MODULE_LICENSE("GPL");
